package cn.supermaster.management.core.component;

import java.util.concurrent.atomic.AtomicInteger;
import javax.annotation.PostConstruct;

import cn.supermaster.management.common.constant.MessageConstant;
import cn.supermaster.management.core.manager.RecordLogManager;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import cn.supermaster.management.common.constant.Constants;
import cn.supermaster.management.common.constant.ShiroConstant;
import cn.supermaster.management.common.domain.SystemUser;
import cn.supermaster.management.common.exception.user.UserPasswordNotMatchException;
import cn.supermaster.management.common.exception.user.UserPasswordRetryLimitExceedException;

/**
 * All rights Reserved, Designed By www.super-bytecode.com
 *
 * @ProjectName: supermaster-management
 * @Package: cn.supermaster.management.core.service
 * @ClassName: PasswordManager
 * @Description: [登录密码验证器]
 * <p> </p>
 * @Author: [Lance Ting]
 * @Date: 2021/1/11 0:38
 * @Version: V1.0
 * @Copyright: 2021 www.super-bytecode.comn Inc. All rights reserved.
 * TODO: 注意,本文件Lance Ting所作,如果转载或使用请标明具体出处!
 **/
@Component
public class PasswordManager {

    /**
     * 日志句柄
     **/
    private final Logger logger = LoggerFactory.getLogger(PasswordManager.class);

    /**
     * 缓存管理器
     **/
    @Autowired
    private CacheManager cacheManager;

    /**
     * 认证信息缓存对象
     **/
    private Cache<String, AtomicInteger> accessRecordCache;

    /**
     * 密码错误次数最大值
     **/
    @Value(value = "${user.password.maxRetryCount}")
    private String maxRetryLimit;

    @PostConstruct
    public void init() {
        logger.info(">>> Access password cache init ...");
        String recordCache = ShiroConstant.LOGINRECORDCACHE;
        accessRecordCache = cacheManager.getCache(recordCache);
    }

    /**
     * @Description: [用户密码有效性校验]
     * <p></P>
     * @Title: checkPasswordEffective
     * @Author: Lance Ting
     * @Date: 2021-01-11
     * @Param: user 用户信息
     * @Param: password 密码
     * @Return: void
     */
    public void checkPasswordEffective(SystemUser user, String password) {
        // 获取用户登录名
        String username = user.getUserName();
        // 获取缓存用户信息
        AtomicInteger retryCount = accessRecordCache.get(username);
        // 密码错误重试消息值
        String passwordRetryLimit = MessageConstant.PASSWORD_RETRY_LIMIT;
        //登录失败状态
        String failStatus = Constants.LOGIN_FAIL;

        // 不存在，则新增缓存信息
        if (retryCount == null) {
            retryCount = new AtomicInteger(0);
            accessRecordCache.put(username, retryCount);
        }

        logger.info(">>> Access password retry count is {} ...", retryCount);
        // 错误次数达到上限值
        int retryLimitInt = Integer.valueOf(maxRetryLimit).intValue();
        if (retryCount.incrementAndGet() > retryLimitInt) {
            RecordLogManager.doRecordLoginInformation(username, failStatus, passwordRetryLimit, maxRetryLimit);
            throw new UserPasswordRetryLimitExceedException(retryLimitInt);
        }

        // 用户密码不匹配
        if (!matches(user, password)) {
            RecordLogManager.doRecordLoginInformation(username, failStatus, passwordRetryLimit, retryCount);
            // 添加认证缓存
            accessRecordCache.put(username, retryCount);
            throw new UserPasswordNotMatchException();
        } else {
            cleanLoginRecordCache(username);
        }
    }

    /**
     * @Description: [密码适配功能]
     * <p></P>
     * @Title: matches
     * @Author: Lance Ting
     * @Date: 2021-01-10
     * @Param: user 用户信息
     * @Param: newPassword 新密码
     * @Return: boolean
     * @Throws:
     */
    public boolean matches(SystemUser user, String newPassword) {

        String userName = user.getUserName();// 登录名
        String password = user.getPassword();// 用户密码
        String salt = user.getSalt();// 加密盐
        // 加密用户密码
        String encryptPassword = encryptPassword(userName, newPassword, salt);
        // 密码适配
        return password.equals(encryptPassword);
    }

    /**
     * @Description: [清空登录缓存]
     * <p></P>
     * @Title: cleanLoginRecordCache
     * @Author: Lance Ting
     * @Date: 2021-01-11
     * @Param: userName
     * @Return: void
     * @Throws:
     */
    public void cleanLoginRecordCache(String username) {
        accessRecordCache.remove(username);
    }

    /**
     * @Description: [加密用户登录密码]
     * <p></P>
     * @Title: encryptPassword
     * @Author: Lance Ting
     * @Date: 2021-01-11
     * @Param: username 登录用户名
     * @Param: password 登录密码
     * @Param: salt 加密盐值
     * @Return: java.lang.String 加密值
     */
    public String encryptPassword(String username, String password, String salt) {
        String target = username + password + salt;
        // 加密
        Md5Hash md5Hash = new Md5Hash(target);
        String encrypt = md5Hash.toHex();
        //
        return encrypt;
    }

}
